#include "cluster.h"

sub_group* create_initial_P(sparse_matrix_lst* A, sub_group** P)
{
	sub_group *isolated_element = NULL, *other_elements = NULL;
	sub_group *last_group = NULL;
	cell_t *curr_cell = NULL;
	int *new_elements_list = NULL, i = 0;

	other_elements = (sub_group*)malloc(sizeof(sub_group));
	other_elements->elements = (int*)calloc(A->n, sizeof(int));
	other_elements->elements_no = 0;
	other_elements->is_divisible = 1;
	other_elements->next = NULL;

	last_group = other_elements;
	*P = other_elements;

	/* Going over all rows - need to go over only */ 
	for (i = 0; i < A->n; ++i)
	{
		curr_cell = A->rows[i];

		/* Found an isolated vertex */
		if (curr_cell == NULL)
		{
			isolated_element = (sub_group*)malloc(sizeof(sub_group));
			isolated_element->elements_no = 1;
			isolated_element->is_divisible = 0;
			isolated_element->elements = (int*)calloc(1, sizeof(int));
			isolated_element->elements[0] = i;
			isolated_element->next = NULL;
			
			last_group->next = isolated_element;
			last_group = last_group->next;
		}
		else
		{
			/* Adding to the other elements list */
			other_elements->elements[other_elements->elements_no] = i;
			++other_elements->elements_no;
		}
	}

	return last_group;
}

void free_P(sub_group* P)
{
	sub_group* curr_group = NULL;

	while(P != NULL)
	{
		curr_group = P;
		P = P->next;
		free(curr_group->elements);
		free(curr_group);
	}
}

void add_to_P(sub_group **P, sub_group **last_sub_group,
			  sub_group *group_to_add)
{
	if (group_to_add->is_divisible || (*last_sub_group) == NULL)
	{
		group_to_add->next = *P;
		(*P) = group_to_add;
		if ((*last_sub_group) == NULL)
			*last_sub_group = *P;
	}
	else
	{
		(*last_sub_group)->next = group_to_add;
		(*last_sub_group) = (*last_sub_group)->next;
		(*last_sub_group)->next = NULL;
		if ((*P) == NULL)
			*P = *last_sub_group;
	}
}


void print_P(sub_group* P, int A_n)
{
	int* indices = NULL;
	int node_to_print = 0, i = 0;
	sub_group* group_to_print = NULL;

	indices = (int*)calloc(A_n, sizeof(int));
	assert(indices != NULL);

	while (node_to_print < A_n)
	{
		group_to_print = find_group_to_print(P, node_to_print);
		print_sub_group(group_to_print);

		for(i = 0; i < group_to_print->elements_no; ++i)
		{
			indices[group_to_print->elements[i]] = 1;
		}

		/* Find the next node that shold be printed */
		while(indices[node_to_print] != 0 && node_to_print < A_n)
			++node_to_print;
	}
	free(indices);
}

sub_group* find_group_to_print(sub_group *P, int first_index)
{
	sub_group* curr_group = P;
	int was_group_found = 0;

	while(curr_group != NULL && !was_group_found)
	{
		if(curr_group->elements[0] == first_index)
		{
			was_group_found = 1;
		}
		else
		{
			curr_group = curr_group->next;
		}
	}

	return curr_group;
}

void print_sub_group(sub_group* group)
{
	print_group(group->elements, group->elements_no);
	printf("\n");
}

void fill_sub_group(sub_group *new_sub_group, int *elements, int elements_no)
{
	new_sub_group->elements = elements;
	new_sub_group->elements_no = elements_no;
	new_sub_group->is_divisible = (elements_no != 1);
	new_sub_group->next = NULL;
}

int count_elements(sub_group *P)
{
	int count = 0;
	sub_group* curr_element = P;

	while(curr_element != NULL)
	{
		++count;
		curr_element = curr_element->next;
	}

	return count;
}

